+++ /dev/null
-#
-#
-# This is free software, licensed under the GNU General Public License v2.
-# See /LICENSE for more information.
-#
-
-include $(TOPDIR)/rules.mk
-
-PKG_NAME:=nft-qos
-PKG_VERSION:=1.0.6
-PKG_RELEASE:=4
-PKG_LICENSE:=GPL-2.0
-
-
-PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
-
-include $(INCLUDE_DIR)/package.mk
-
-define Package/nft-qos
- SECTION:=utils
- CATEGORY:=Base system
- DEPENDS:=+kmod-nft-netdev +kmod-nft-bridge +nftables
- TITLE:=QoS scripts over nftables
- PKGARCH:=all
-endef
-
-define Package/nft-qos/description
- This package provides implementation for qos over nftables.
- Currently, static/dynamic qos and traffic shaping are supported.
-endef
-
-define Package/nft-qos/conffiles
-/etc/config/nft-qos
-endef
-
-define Build/Prepare
-endef
-
-define Build/Configure
-endef
-
-define Build/Compile
-endef
-
-define Package/nft-qos/install
- $(INSTALL_DIR) $(1)/lib/nft-qos
- $(INSTALL_DATA) ./files/lib/* $(1)/lib/nft-qos/
- $(INSTALL_DIR) $(1)/etc/config
- $(INSTALL_CONF) ./files/nft-qos.config $(1)/etc/config/nft-qos
- $(INSTALL_DIR) $(1)/etc/init.d
- $(INSTALL_BIN) ./files/nft-qos.init $(1)/etc/init.d/nft-qos
- $(INSTALL_DIR) $(1)/etc/hotplug.d/dhcp
- $(INSTALL_BIN) ./files/nft-qos-monitor.hotplug $(1)/etc/hotplug.d/dhcp/00-nft-qos-monitor
- $(INSTALL_BIN) ./files/nft-qos-dynamic.hotplug $(1)/etc/hotplug.d/dhcp/01-nft-qos-dynamic
-endef
-
-$(eval $(call BuildPackage,nft-qos))
+++ /dev/null
-#!/bin/sh
-#
-#
-
-# for uci_validate_section()
-. /lib/functions/procd.sh
-
-NFT_QOS_HAS_BRIDGE=
-NFT_QOS_INET_FAMILY=ip
-NFT_QOS_SCRIPT_TEXT=
-NFT_QOS_SCRIPT_FILE=/tmp/qos.nft
-
-qosdef_appendx() { # <string to be appended>
- NFT_QOS_SCRIPT_TEXT="$NFT_QOS_SCRIPT_TEXT""$1"
-}
-
-qosdef_append_chain_def() { # <type> <hook> <priority> <policy>
- qosdef_appendx "\t\ttype $1 hook $2 priority $3; policy $4;\n"
-}
-
-qosdef_append_chain_ingress() { # <type> <device> <priority> <policy>
- qosdef_appendx "\t\ttype $1 hook ingress device $2 priority $3; policy $4;\n"
-}
-
-# qosdef_append_rule_{MATCH}_{STATEMENT}
-qosdef_append_rule_ip_limit() { # <ipaddr> <operator> <unit> <rate>
- local ipaddr=$1
- local operator=$2
- local unit=$3
- local rate=$4
-
- qosdef_appendx \
- "\t\tip $operator $ipaddr limit rate over $rate $unit/second drop\n"
-}
-
-# qosdef_append_rule_{MATCH}_{STATEMENT}
-qosdef_append_rule_mac_limit() { # <macaddr> <operator> <unit> <rate>
- local macaddr=$1
- local operator=$2
- local unit=$3
- local rate=$4
-
- qosdef_appendx \
- "\t\tether $operator $macaddr limit rate over $rate $unit/second drop\n"
-}
-
-# qosdef_append_rule_{MATCH}_{POLICY}
-qosdef_append_rule_ip_policy() { # <operator> <ipaddr> <policy>
- qosdef_appendx "\t\tip $1 $2 $3\n"
-}
-
-_handle_limit_whitelist() { # <value> <chain>
- local ipaddr=$1
- local operator
-
- [ -z "$ipaddr" ] && return
-
- case "$2" in
- download) operator="daddr";;
- upload) operator="saddr";;
- esac
-
- qosdef_append_rule_ip_policy $operator $ipaddr accept
-}
-
-qosdef_append_rule_limit_whitelist() { # <chain>
- config_list_foreach default limit_whitelist _handle_limit_whitelist $1
-}
-
-qosdef_flush_table() { # <family> <table>
- nft flush table $1 $2 2>/dev/null
-}
-
-qosdef_remove_table() { # <family> <table>
- nft delete table $1 $2 2>/dev/null
-}
-
-qosdef_init_header() { # add header for nft script
- qosdef_appendx "#!/usr/sbin/nft -f\n"
- qosdef_appendx "#\n\n"
-}
-
-qosdef_init_env() {
- # check interface type of lan
- local lt="$(uci_get "network.lan.type")"
- [ "$lt" = "bridge" ] && export NFT_QOS_HAS_BRIDGE="y"
-
- # check if ipv6 support
- [ -e /proc/sys/net/ipv6 ] && export NFT_QOS_INET_FAMILY="inet"
-}
-
-qosdef_clean_cache() {
- rm -f $NFT_QOS_SCRIPT_FILE
-}
-
-qosdef_init_done() {
- echo -e $NFT_QOS_SCRIPT_TEXT > $NFT_QOS_SCRIPT_FILE 2>/dev/null
-}
-
-qosdef_start() {
- nft -f $NFT_QOS_SCRIPT_FILE 2>/dev/null
-}
+++ /dev/null
-#!/bin/sh
-#
-#
-
-. /lib/nft-qos/core.sh
-
-qosdef_validate_dynamic() {
- uci_load_validate nft-qos default "$1" "$2" \
- 'limit_enable:bool:0' \
- 'limit_type:maxlength(8)' \
- 'dynamic_bw_up:uinteger:100' \
- 'dynamic_bw_down:uinteger:100'
-}
-
-# return average rate for dhcp leases
-qosdef_dynamic_rate() { # <bandwidth>
- local c=0 c6=0
-
- [ ! -e /tmp/dhcp.leases -a \
- ! -e /var/dhcp6.leases ] && return
-
- [ -e /tmp/dhcp.leases ] && \
- c=$(wc -l < /tmp/dhcp.leases 2>/dev/null)
- [ -e /var/dhcp6.leases ] && \
- c6=$(wc -l < /var/dhcp6.leases 2>/dev/null)
- [ $c -eq 0 -a $c6 -eq 0 ] && \
- { echo 12500; return; }
-
- echo $(($1 / ($c + $c6)))
-}
-
-qosdef_append_chain_dym() { # <hook> <name> <bandwidth>
- local cidr cidr6
- local operator rate
- local hook=$1 name=$2 bandwidth=$3
-
- config_get cidr default 'dynamic_cidr'
- config_get cidr6 default 'dynamic_cidr6'
-
- [ -z "$cidr" -a -z "$cidr6" ] && return
-
- case "$2" in
- download) operator=daddr;;
- upload) operator=saddr;;
- esac
-
- rate=$(qosdef_dynamic_rate $bandwidth)
-
- qosdef_appendx "\tchain $name {\n"
- qosdef_append_chain_def filter $hook 0 accept
- qosdef_append_rule_limit_whitelist $name
- [ -n "$cidr" ] && \
- qosdef_append_rule_ip_limit $cidr $operator kbytes $rate
- [ -n "$cidr6" ] && \
- qosdef_append_rule_ip_limit $cidr6 $operator kbytes $rate
- qosdef_appendx "\t}\n"
-}
-
-qosdef_flush_dynamic() {
- qosdef_flush_table "$NFT_QOS_INET_FAMILY" nft-qos-dynamic
-}
-
-# init dynamic qos
-qosdef_init_dynamic() {
- local hook_ul="prerouting" hook_dl="postrouting"
-
- [ "$2" = 0 ] || {
- logger -t nft-qos-dynamic "validation failed"
- return 1
- }
-
- [ $limit_enable -eq 0 -o \
- "$limit_type" = "static" ] && return 1
-
- # Transfer mbits/s to mbytes/s
- # e.g. 100,000 kbits == 12,500 kbytes
- dynamic_bw_up=$(($dynamic_bw_up * 1000 / 8))
- dynamic_bw_down=$(($dynamic_bw_down * 1000 / 8))
-
- [ -z "$NFT_QOS_HAS_BRIDGE" ] && {
- hook_ul="postrouting"
- hook_dl="prerouting"
- }
-
- qosdef_appendx "table $NFT_QOS_INET_FAMILY nft-qos-dynamic {\n"
- qosdef_append_chain_dym $hook_ul upload $dynamic_bw_up
- qosdef_append_chain_dym $hook_dl download $dynamic_bw_down
- qosdef_appendx "}\n"
-}
+++ /dev/null
-#!/bin/sh
-# based on static.sh
-#
-
-. /lib/nft-qos/core.sh
-
-qosdef_validate_mac() {
- uci_load_validate nft-qos default "$1" "$2" \
- 'limit_mac_enable:bool:0'
-}
-
-# append rule for mac qos
-qosdef_append_rule_mac() { # <section> <operator>
- local macaddr unit rate
- local operator=$2
-
- config_get macaddr $1 macaddr
- if [ "$operator" = "saddr" ]; then
- config_get unit $1 urunit
- config_get rate $1 urate
- else
- config_get unit $1 drunit
- config_get rate $1 drate
- fi
-
- [ -z "$macaddr" ] && return
-
- qosdef_append_rule_mac_limit $macaddr $operator $unit $rate
-}
-
-# append chain for mac qos
-qosdef_append_chain_mac() { # <hook> <name> <section>
- local hook=$1 name=$2
- local config=$3 operator
-
- case "$name" in
- download) operator="daddr";;
- upload) operator="saddr";;
- esac
-
- qosdef_appendx "\tchain $name {\n"
- qosdef_append_chain_def filter $hook 0 accept
- config_foreach qosdef_append_rule_mac $config $operator
- qosdef_appendx "\t}\n"
-}
-
-qosdef_flush_mac() {
- if [ -n "$NFT_QOS_HAS_BRIDGE" ]; then
- qosdef_flush_table bridge nft-qos-mac
- else
- qosdef_flush_table "$NFT_QOS_INET_FAMILY" nft-qos-mac
- fi
-}
-
-# limit rate by mac address init
-qosdef_init_mac() {
- local hook_ul="prerouting" hook_dl="postrouting"
-
- [ "$2" = 0 ] || {
- logger -t nft-qos-mac "validation failed"
- return 1
- }
-
- [ $limit_mac_enable -eq 0 ] && return 1
-
- table_name=$NFT_QOS_INET_FAMILY
- if [ -z "$NFT_QOS_HAS_BRIDGE" ]; then
- hook_ul="postrouting"
- hook_dl="prerouting"
- else
- table_name="bridge"
- fi
-
- qosdef_appendx "table $table_name nft-qos-mac {\n"
- qosdef_append_chain_mac $hook_ul upload client
- qosdef_append_chain_mac $hook_dl download client
- qosdef_appendx "}\n"
-}
+++ /dev/null
-#!/bin/sh
-#
-#
-
-. /lib/nft-qos/core.sh
-
-qosdef_monitor_get_ip_handle() { # <family> <chain> <ip>
- echo $(nft -a list chain $1 nft-qos-monitor $2 2>/dev/null | grep $3 | awk '{print $11}')
-}
-
-qosdef_monitor_add() { # <mac> <ip> <hostname>
- handle_dl=$(qosdef_monitor_get_ip_handle $NFT_QOS_INET_FAMILY download $2)
- [ -z "$handle_dl" ] && nft add rule $NFT_QOS_INET_FAMILY nft-qos-monitor download ip daddr $2 counter
- handle_ul=$(qosdef_monitor_get_ip_handle $NFT_QOS_INET_FAMILY upload $2)
- [ -z "$handle_ul" ] && nft add rule $NFT_QOS_INET_FAMILY nft-qos-monitor upload ip saddr $2 counter
-}
-
-qosdef_monitor_del() { # <mac> <ip> <hostname>
- local handle_dl handle_ul
- handle_dl=$(qosdef_monitor_get_ip_handle $NFT_QOS_INET_FAMILY download $2)
- handle_ul=$(qosdef_monitor_get_ip_handle $NFT_QOS_INET_FAMILY upload $2)
- [ -n "$handle_dl" ] && nft delete handle $handle_dl
- [ -n "$handle_ul" ] && nft delete handle $handle_ul
-}
-
-# init qos monitor
-qosdef_init_monitor() {
- local hook_ul="prerouting" hook_dl="postrouting"
-
- [ -z "$NFT_QOS_HAS_BRIDGE" ] && {
- hook_ul="postrouting"
- hook_dl="prerouting"
- }
-
- nft add table $NFT_QOS_INET_FAMILY nft-qos-monitor
- nft add chain $NFT_QOS_INET_FAMILY nft-qos-monitor upload { type filter hook $hook_ul priority 0\; }
- nft add chain $NFT_QOS_INET_FAMILY nft-qos-monitor download { type filter hook $hook_dl priority 0\; }
-}
+++ /dev/null
-#!/bin/sh
-#
-#
-
-. /lib/functions/network.sh
-. /lib/nft-qos/core.sh
-
-P1=""; P2=""; P3=""; P4=""; P5=""; P6="";
-P7=""; P8=""; P9=""; P10=""; P11="";
-
-qosdef_validate_priority() {
- uci_load_validate nft-qos default "$1" "$2" \
- 'priority_enable:bool:0' \
- 'priority_netdev:maxlength(8)'
-}
-
-_qosdef_handle_protox() { # <priority> <rule>
- case "$1" in
- -400) P1="$P1""$2";;
- -300) P2="$P2""$2";;
- -225) P3="$P3""$2";;
- -200) P4="$P4""$2";;
- -150) P5="$P5""$2";;
- -100) P6="$P6""$2";;
- 0) P7="$P7""$2";;
- 50) P8="$P8""$2";;
- 100) P9="$P9""$2";;
- 225) P10="$P10""$2";;
- 300) P11="$P11""$2";;
- esac
-}
-
-qosdef_handle_protox() { # <section>
- local proto prio srv
-
- config_get proto $1 'protocol'
- config_get prio $1 'priority'
- config_get srv $1 'service'
-
- [ -z "$proto" -o \
- -z "$prio" -o \
- -z "$srv" ] && return
-
- _qosdef_handle_protox $prio \
- "\t\t$proto dport { $srv } accept\n"
-}
-
-qosdef_append_rule_protox() { # <section>
- config_foreach qosdef_handle_protox $1
- qosdef_appendx \
- "${P1}${P2}${P3}${P4}${P5}${P6}${P7}${P8}${P9}${P10}${P11}"
-}
-
-qosdef_append_chain_priority() { # <name> <section> <device>
- local name=$1 device=$3
-
- qosdef_appendx "\tchain $name {\n"
- qosdef_append_chain_ingress filter $device 0 accept
- qosdef_append_rule_protox $2
- qosdef_appendx "\t}\n"
-}
-
-qosdef_remove_priority() {
- qosdef_remove_table netdev nft-qos-priority
-}
-
-# init traffic priority
-qosdef_init_priority() {
- [ "$2" = 0 ] || {
- logger -t nft-qos-priority "validation failed"
- return 1
- }
-
- [ $priority_enable -eq 0 ] && return 1
-
- local ifname
- network_get_device ifname "$priority_netdev"
- [ -n "$ifname" ] || {
- logger -t nft-qos-priority "unable to get ifname for $priority_netdev"
- return 1
- }
-
- qosdef_appendx "table netdev nft-qos-priority {\n"
- qosdef_append_chain_priority filter priority $ifname
- qosdef_appendx "}\n"
-}
+++ /dev/null
-#!/bin/sh
-#
-#
-
-. /lib/nft-qos/core.sh
-
-qosdef_validate_static() {
- uci_load_validate nft-qos default "$1" "$2" \
- 'limit_enable:bool:0' \
- 'limit_type:maxlength(8)' \
- 'static_unit_dl:string:kbytes' \
- 'static_unit_ul:string:kbytes' \
- 'static_rate_dl:uinteger:50' \
- 'static_rate_ul:uinteger:50'
-}
-
-# append rule for static qos
-qosdef_append_rule_sta() { # <section> <operator> <default-unit> <default-rate>
- local ipaddr unit rate
- local operator=$2
-
- config_get ipaddr $1 ipaddr
- config_get unit $1 unit $3
- config_get rate $1 rate $4
-
- [ -z "$ipaddr" ] && return
-
- qosdef_append_rule_ip_limit $ipaddr $operator $unit $rate
-}
-
-# append chain for static qos
-qosdef_append_chain_sta() { # <hook> <name> <section> <unit> <rate>
- local hook=$1 name=$2
- local config=$3 operator
-
- case "$name" in
- download) operator="daddr";;
- upload) operator="saddr";;
- esac
-
- qosdef_appendx "\tchain $name {\n"
- qosdef_append_chain_def filter $hook 0 accept
- qosdef_append_rule_limit_whitelist $name
- config_foreach qosdef_append_rule_sta $config $operator $4 $5
- qosdef_appendx "\t}\n"
-}
-
-qosdef_flush_static() {
- qosdef_flush_table "$NFT_QOS_INET_FAMILY" nft-qos-static
-}
-
-# static limit rate init
-qosdef_init_static() {
- local hook_ul="prerouting" hook_dl="postrouting"
-
- [ "$2" = 0 ] || {
- logger -t nft-qos-static "validation failed"
- return 1
- }
-
- [ $limit_enable -eq 0 -o \
- $limit_type = "dynamic" ] && return 1
-
- [ -z "$NFT_QOS_HAS_BRIDGE" ] && {
- hook_ul="postrouting"
- hook_dl="prerouting"
- }
-
- qosdef_appendx "table $NFT_QOS_INET_FAMILY nft-qos-static {\n"
- qosdef_append_chain_sta $hook_ul upload upload $static_unit_ul $static_rate_ul
- qosdef_append_chain_sta $hook_dl download download $static_unit_dl $static_rate_dl
- qosdef_appendx "}\n"
-}
+++ /dev/null
-#!/bin/sh
-#
-#
-
-export initscript="nft-qos-dynamic"
-
-. /lib/functions.sh
-. /lib/nft-qos/core.sh
-. /lib/nft-qos/dynamic.sh
-
-NFT_QOS_DYNAMIC_ON=
-
-qosdef_check_if_dynamic() {
- [ $limit_enable -eq 1 -a \
- "$limit_type" = "dynamic" ] && \
- NFT_QOS_DYNAMIC_ON="y"
-}
-
-
-logger -t nft-qos-dynamic "ACTION=$ACTION, MACADDR=$MACADDR, IPADDR=$IPADDR, HOSTNAME=$HOSTNAME"
-
-case "$ACTION" in
- add | update | remove)
- qosdef_validate_dynamic default qosdef_check_if_dynamic
- [ -z "$NFT_QOS_DYNAMIC_ON" ] && return
-
- qosdef_init_env
- qosdef_flush_dynamic
-
- qosdef_init_header
- qosdef_validate_dynamic default qosdef_init_dynamic
- qosdef_init_done
- qosdef_start
- ;;
-esac
+++ /dev/null
-#!/bin/sh
-#
-#
-
-export initscript="nft-qos-monitor"
-
-. /lib/nft-qos/monitor.sh
-
-logger -t nft-qos-monitor "ACTION=$ACTION, MACADDR=$MACADDR, IPADDR=$IPADDR, HOSTNAME=$HOSTNAME"
-
-case "$ACTION" in
- add | update)
- qosdef_init_env
- qosdef_init_monitor
- qosdef_monitor_add $MACADDR $IPADDR $HOSTNAME
- ;;
- remove)
- qosdef_init_env
- qosdef_init_monitor
- qosdef_monitor_del $MACADDR $IPADDR $HOSTNAME
- ;;
-esac
+++ /dev/null
-#
-#
-# This is the sample for nft-qos configuration file,
-# which will generate a nftables script in /tmp/qos.nft
-#
-
-# Getting Started
-# Official site :
-# https://netfilter.org/projects/nftables/index.html
-# What is nftables :
-# https://wiki.nftables.org/wiki-nftables/index.php/Main_Page
-#
-
-# Basic Operations
-# Configuring Tables :
-# https://wiki.nftables.org/wiki-nftables/index.php/Configuring_tables
-# Configuring Chains :
-# https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains
-# Configuring Rules :
-# https://wiki.nftables.org/wiki-nftables/index.php/Simple_rule_management
-# Quick Reference (recommended) :
-# https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes
-# https://netfilter.org/projects/nftables/manpage.html
-#
-
-config default default
- # Enable Flag for limit rate
- option limit_enable '1'
-
- # Options for enable Static QoS (rate limit)
- option limit_type 'static'
- # Options for Static QoS (rate limit)
- option static_unit_dl 'kbytes'
- option static_unit_ul 'kbytes'
- option static_rate_dl '50'
- option static_rate_ul '50'
-
- # Options for enable Dynamic QoS
- # This option can not compatible with Static QoS
- # option limit_type 'dynamic'
-
- # For Dynamic QoS Samples (unit of bandwidth is Mbps):
- option dynamic_cidr '192.168.1.0/24'
- option dynamic_cidr6 'AAAA:BBBB::1/64'
- option dynamic_bw_up '100'
- option dynamic_bw_down '100'
-
- # White list for static/dynamic limit
- # list limit_whitelist '192.168.1.225'
- # list limit_whitelist '192.168.1.0/24'
- # list limit_whitelist 'ABCD:CDEF::1/64'
-
- # Option for Mac address based traffic control
- option limit_mac_enable '0'
-
- # Options for Traffic Priority
- option priority_enable '0'
- option priority_netdev 'lan'
-
-
-#
-# For Static QoS Rate Limit Samples :
-#
-# For Download :
-#config download
-# option hostname 'My PC'
-# option unit 'kbytes'
-# option ipaddr '192.168.1.224'
-# option rate '128'
-#
-# For Upload :
-#config upload
-# option hostname 'office-pc'
-# option unit 'mbytes'
-# option ipaddr 'ABCD:FFED::1/64'
-# option rate '1024'
-#
-# For MAC address based traffic control Samples :
-#
-#config client
-# option drunit 'kbytes'
-# option urunit 'kbytes'
-# option hostname 'tvbox'
-# option macaddr '00:00:00:00:00:00'
-# option drate '300'
-# option urate '30'
-#
-# Traffic Priority Samples :
-#
-# protocol : tcp, udp, udplite, sctp, dccp, tcp is default
-# priority : integer between 1-11, 1 is default and the highest
-# service : you can input a integer or service name,
-# e.g. '22', '11-22', 'telnet', 'ssh, http, ftp', etc
-#
-#config priority
-# option protocol 'tcp'
-# option priority '-400'
-# option service '23'
-# option comment '?'
-#
-#config priority
-# option protocol 'udp'
-# option priority '-400'
-# option service 'https'
-# option comment '?'
-#
-#config priority
-# option protocol 'dccp'
-# option priority '0'
-# option service '22-35'
-# option comment '?'
-#
-#config priority
-# option protocol 'dccp'
-# option priority '300'
-# option service 'ftp,ssh,http'
-# option comment '?'
-#
+++ /dev/null
-#!/bin/sh /etc/rc.common
-#
-#
-
-if [ -z "${IPKG_INSTROOT}" ]; then
- . /lib/nft-qos/core.sh
- . /lib/nft-qos/monitor.sh
- . /lib/nft-qos/dynamic.sh
- . /lib/nft-qos/static.sh
- . /lib/nft-qos/mac.sh
- . /lib/nft-qos/priority.sh
-fi
-
-START=99
-USE_PROCD=1
-
-service_triggers() {
- procd_add_reload_trigger nft-qos
-
- procd_open_validate
- qosdef_validate_dynamic
- qosdef_validate_static
- qosdef_validate_priority
- qosdef_validate_mac
- procd_close_validate
-}
-
-start_service() {
- config_load nft-qos
-
- qosdef_init_env
- qosdef_flush_mac
- qosdef_flush_static
- qosdef_flush_dynamic
- qosdef_remove_priority
-
- qosdef_init_header
- qosdef_init_monitor
- qosdef_validate_dynamic default qosdef_init_dynamic
- qosdef_validate_static default qosdef_init_static
- qosdef_validate_mac default qosdef_init_mac
- qosdef_validate_priority default qosdef_init_priority
- qosdef_init_done
- qosdef_start
-}
-
-stop_service() {
- qosdef_flush_dynamic
- qosdef_flush_static
- qosdef_flush_mac
- qosdef_remove_priority
- qosdef_clean_cache
-}